package edu.snake.implement.service;

import edu.snake.core.GameEngine;
import edu.snake.core.model.arena.Arena;
import edu.snake.core.model.arena.Position;
import edu.snake.core.model.character.Character;
import edu.snake.core.service.MoveAndCollisionController;
import edu.snake.core.service.ViewController;
import edu.snake.implement.model.CharacterName;
import edu.snake.implement.utils.PairCharacter;

import java.awt.event.ActionEvent;
import java.util.concurrent.locks.Lock;

import static edu.snake.implement.ConfigConstant.getInstanceFactory;


public class MoveAndCollisionControllerImpl implements MoveAndCollisionController {

    private final GameEngine gameEngine;
    private final ViewController viewController;


    public MoveAndCollisionControllerImpl(GameEngine gameEngine, ViewController viewController) {
        this.gameEngine = gameEngine;
        this.viewController = viewController;
    }

    @Override
    public void move() {
        Arena arena = gameEngine.getArena();
        viewController.renderArena(arena);
    }


    @Override
    public void collision(Character who, Character whom) {
        if (who.getName() == CharacterName.SNAKE_HEAD) {
            if (whom.getName().toString().contains(CharacterName.BORDER.toString())
                    || whom.getName().toString().contains(CharacterName.SNAKE.toString())) {
                who.setAlive(false);
                viewController.endGameRender(gameEngine.getArena());
                gameEngine.stopGame();
            }
            if (whom.getName() == CharacterName.FROG) {
                int score = gameEngine.getScore();
                score++;
                gameEngine.setScore(score);
                gameEngine.killCharacter(whom);
                snakeGrow(who);
                viewController.incrementScore(score);
                gameEngine.createCharacter(CharacterName.FROG);
                move();
            }
        }

    }

    private void snakeGrow(Character who) {
        int size = who.size();
        Arena arena = gameEngine.getArena();
        Character snake_tail = who.getChild(size - 2); //todo magic number The size of the character includes parental element therefore  size minus two, Correct to use the iterator.
        Lock lock = arena.getLock();
        lock.lock();
        try {
            Position positionSnakeTail = arena.get(snake_tail);
            arena.set(positionSnakeTail, null);
            who.remove(snake_tail);
            Character character = getInstanceFactory().createNewCharacter(CharacterName.SNAKE);
            who.add(character);
            arena.set(positionSnakeTail, character);
            who.add(snake_tail);
            positionSnakeTail = arena.calculateNeighboringFreePosition(positionSnakeTail);
            arena.set(positionSnakeTail, snake_tail);
        } finally {
            lock.unlock();
        }
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("moved")) {
            move();
        }
        if (e.getActionCommand().equals("collision")) {
            Character who = ((PairCharacter) e.getSource()).getFirst();
            Character whom = ((PairCharacter) e.getSource()).getSecond();
            collision(who, whom);
        }
    }
}
